package com.sgzn.sgpay.service.impl;

import com.sgzn.sgpay.enums.*;
import com.sgzn.sgpay.exception.SgpayException;
import com.sgzn.sgpay.model.request.*;
import com.sgzn.sgpay.model.response.SgsResultResponse;
import com.sgzn.sgpay.model.response.SgsUserInfoQueryResponse;
import com.sgzn.sgpay.model.response.vo.DeviceInfoVo;
import com.sgzn.sgpay.persistence.dao.SequenceMapper;
import com.sgzn.sgpay.persistence.dao.TBizOrderMapper;
import com.sgzn.sgpay.persistence.dao.TMainOrderMapper;
import com.sgzn.sgpay.persistence.dao.TShowIncomeRecordMapper;
import com.sgzn.sgpay.persistence.domain.*;
import com.sgzn.sgpay.service.*;
import com.sgzn.sgpay.service.converter.AssembleSgsCommonHandle;
import com.sgzn.sgpay.service.support.SgsResponseUtil;
import com.sgzn.sgpay.service.tcp.api.TcpConsumeService;
import com.sgzn.sgpay.service.tcp.api.TcpIncreaseCreditService;
import com.sgzn.sgpay.service.tcp.model.terminal.request.TcpIncreaseCreditRequest;
import com.sgzn.sgpay.util.ArgsUtils;
import com.sgzn.sgpay.util.SeqUtil;
import com.sgzn.sgpay.util.TranslateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * 上分服务
 * @author zhongzhongyong
 * @version Id: SgsMchAccountService.java, v 0.1 2018/4/17 21:50 zhongzhongyong Exp $$
 */
@Service
@Slf4j
public class SgsIncreaseCreditServiceImpl implements SgsIncreaseCreditService {

    @Autowired
    private SgsDeviceService sgsDeviceService;

    @Autowired
    private SgsUserInfoService sgsUserInfoService;

    @Autowired
    private TcpConsumeService tcpConsumeService;

    @Autowired
    private TcpIncreaseCreditService tcpIncreaseCreditService;

    @Autowired
    private TMainOrderMapper tMainOrderMapper;

    @Autowired
    private TBizOrderMapper tBizOrderMapper;

    @Autowired
    private SgsMerchantDiscountRuleService sgsMerchantDiscountRuleService;

    @Autowired
    private AssembleSgsCommonHandle assembleSgsCommonHandle;

    @Autowired
    private SgsUserMerchantDiscountService sgsUserMerchantDiscountService;

    @Autowired
    private TShowIncomeRecordMapper tShowIncomeRecordMapper;


    /**
     * 统一序列生成Mapper
     */
    @Resource
    private SequenceMapper sequenceMapper;

    /**
     * 上分调用
     * @param request
     * @return
     */
    @Override
    @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SgsResultResponse<String> invoke(SgsIncreaseCreditRequest request) {
        try{
            BigDecimal trsAmount = new BigDecimal(request.getTrsAmount());
            //检查相同的deviceId是否存在“待回调”状态的上分订单
            checkUniqueOrder(request.getDeviceId());
            //根据设备ID，找到商户ID，再根据商户ID找到有效的商户账户信息【若出现商户信息不符的情况，会直接打断并返回异常信息】
            DeviceInfoVo device = getDevice(request);
            ArgsUtils.notNull(device,
                    SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseCode(),
                    SgsResponseCode.C_DEVICE_NOT_FOUND.getResponseDesc());
            //根据token获取有效用户ID和用户账户信息
            //  检查本次消费积分是否小于等于用户剩余积分【若出现状态不符或者积分不符的情况，会打断流程并返回异常信息】
            SgsUserInfoQueryResponse userInfo = getUserInfo(request);
            ArgsUtils.notNull(userInfo,
                    SgsResponseCode.C_USER_NOT_FOUND.getResponseCode(),
                    SgsResponseCode.C_USER_NOT_FOUND.getResponseDesc());
            //判断用户是否充值
            ArgsUtils.notNull(userInfo.getAccountAmount(),
                    SgsResponseCode.C_USER_ACCOUNT_NOT_FOUND.getResponseCode(),
                    SgsResponseCode.C_USER_ACCOUNT_NOT_FOUND.getResponseDesc());
            request.setMerchantId(device.getMerchantId());
            SgsResultResponse<List<TMerchantDiscountRule>> ruleResp = getListSgsResultResponse(request);
            if (TranslateUtil.isSuccessAbs(ruleResp.getErrorCode()) && ruleResp.getResult() != null) {
                request.setRuleList(ruleResp.getResult());
            }
            boolean flag = false;
            int totalDiscount = 0;
            if (!CollectionUtils.isEmpty(request.getRuleList())) {//检查MerchId有没有消费优惠规则,
                log.info("ruleList:",request.getRuleList());

                //检查UserId在MerchId累计消费是否达到赠送标准
                List<TBizOrder> tBizOrders = gettBizOrders(request);
                BigDecimal totalRecordAmount = new BigDecimal(0);//用户累计消费
                for (TBizOrder tBizOrder : tBizOrders) {
                    totalRecordAmount.add(tBizOrder.getBizAmount());
                }
                request.setTotalRecordAmount(totalRecordAmount);
                log.info("用户累计消费：{}", totalRecordAmount);
                //查询
                SgsResultResponse<TUserMerchantDiscount> discountSgsResultResponse = queryDiscount(request);
                if (TranslateUtil.isSuccessAbs(discountSgsResultResponse.getErrorCode()) && discountSgsResultResponse.getResult() != null) {
                    request.setHadDiscountLevel(discountSgsResultResponse.getResult().getHadDiscountLevel());
                }
                int discountRule = getDiscountRule(request);

                if (discountRule > 0) {
                    //如果达到,先判断是否已经送过，将送分计入用户商户子账户t_user_merchant_discount
                    if(TranslateUtil.isSuccessAbs(discountSgsResultResponse.getErrorCode()) && discountSgsResultResponse.getResult() != null){
                        TUserMerchantDiscount result = discountSgsResultResponse.getResult();
                        Integer discountAccountAmount = result.getDiscountAccountAmount();
                        totalDiscount = discountAccountAmount + discountRule;
                        //用户商户子账户有记录
                        //修改 调用Increase接口
                        SgsResultResponse<String> increaseSgsResultResponse = invokeIncreaseUserMerchantDiscount(request, totalDiscount);
                        if(TranslateUtil.isSuccessAbs(increaseSgsResultResponse.getErrorCode()) && increaseSgsResultResponse.getResult() != null){
                            flag = true;
                            log.info("累加用户商户优惠积分 success");
                        } else {
                            log.info("累加用户商户优惠积分 fail:{}", increaseSgsResultResponse);
                        }
                    }
                    if(SgsResponseCode.C_USER_MERCHANT_NOT_FOUND.getResponseCode().equals(discountSgsResultResponse.getErrorCode())){
                        //新增
                        totalDiscount = discountRule;
                        SgsResultResponse<String> stringSgsResultResponse = iniUserMerchantDiscount(request, totalDiscount);
                        if(TranslateUtil.isSuccessAbs(stringSgsResultResponse.getErrorCode()) && stringSgsResultResponse.getResult() != null){
                            flag = true;
                            log.info("初始化用户商户优惠记录 success");
                        } else {
                            log.info("初始化用户商户优惠记录 fail:{}", stringSgsResultResponse);
                        }
                    }

                }

            }

            if (flag) {
                // decreaseUserMerchantDiscount  上分的时候修改 判断逻辑
                SgsUserMerchantDiscountRequest sgsUserMerchantDiscountRequest = new SgsUserMerchantDiscountRequest();
                assembleSgsCommonHandle.assemble(request, sgsUserMerchantDiscountRequest);
                sgsUserMerchantDiscountRequest.setMerchantId(request.getMerchantId());
                sgsUserMerchantDiscountRequest.setUserId(userInfo.getUserId());
                String trsAmountTemp = request.getTrsAmount();//消费积分
                ArgsUtils.notNegative(userInfo.getAccountAmount().add(new BigDecimal(totalDiscount)).compareTo(trsAmount),
                        SgsResponseCode.C_BALANCE_NOT_ENOUGH.getResponseCode(),
                        SgsResponseCode.C_BALANCE_NOT_ENOUGH.getResponseDesc());//判断积分是否足够
                int leavings = totalDiscount-Integer.parseInt(trsAmountTemp);
                if (leavings > 0) {
                    sgsUserMerchantDiscountRequest.setDiscountAmount(String.valueOf(leavings));
                } else {
                    sgsUserMerchantDiscountRequest.setDiscountAmount(String.valueOf(0));
                }
                sgsUserMerchantDiscountService.decreaseUserMerchantDiscount(sgsUserMerchantDiscountRequest);
            } else {
                ArgsUtils.notNegative(userInfo.getAccountAmount().compareTo(trsAmount),
                        SgsResponseCode.C_BALANCE_NOT_ENOUGH.getResponseCode(),
                        SgsResponseCode.C_BALANCE_NOT_ENOUGH.getResponseDesc());//判断积分是否足够
            }

            //3.下单：主单和业务单，单状态均为初始化,需要把设备ID、本次消费积分和token保存到业务单中【若下单出现异常，会打断流程并返回异常信息】
            TBizOrder tBizOrder = this.settleOrder(request,device);

            //收益记录
            updateTShowIncomeRecord(request, trsAmount);

            //4.调用Tcp上分口,并更新订单状态为"处理中"
            if( invokeTcpIncreaseCredit(request,device.getDeviceId(),tBizOrder.getOrderId())){
                //更新订单状态为待回调AFT
                updateOrder(tBizOrder);
                return SgsResponseUtil.INSTANCE.success("success");
            }else{
                throw new SgpayException(SgsResponseCode.C_TCP_CONSUME_FAIL.getResponseCode(),SgsResponseCode.C_TCP_CONSUME_FAIL.getResponseDesc());
            }

        }catch(SgpayException e){
            log.error(" 上分业务异常 {},{}",e.getCode(),e.getDesc());
            return SgsResponseUtil.INSTANCE.fail(e.getCode(),e.getDesc());
        }catch (Exception e){
            log.error(" 上分系统异常.",e);
            return SgsResponseUtil.INSTANCE.fail(SgsResponseCode.C503.getResponseCode(),SgsResponseCode.C503.getResponseDesc());
        }
    }

    /**
     * 检查是否已存在待回调的上分订单
     * @param deviceId
     */
    private void checkUniqueOrder(String deviceId){
        TBizOrderExample tBizOrderExample = new TBizOrderExample();
        TBizOrderExample.Criteria cra = tBizOrderExample.createCriteria();
        cra.andOrderDeviceEqualTo(deviceId);
        cra.andBizStateEqualTo(OrderStateEnum.SM_AFT.getCode());
        cra.andBizTypeEqualTo(OrderTypeEnum.INCREASE_CREDIT.getCode());
        List<TBizOrder> orderList = tBizOrderMapper.selectByExample(tBizOrderExample);
        if(orderList != null){
            ArgsUtils.notPositive(orderList.size(), SgsResponseCode.C_CRED_INC_ORDER_EXIST.getResponseCode(),
                    SgsResponseCode.C_CRED_INC_ORDER_EXIST.getResponseDesc());
        }
    }

    /**
     * 更新今日收益 和 累计收益 记录
     * @param request
     * @param trsAmount
     */
    private void updateTShowIncomeRecord(SgsIncreaseCreditRequest request, BigDecimal trsAmount) {
        TShowIncomeRecordExample example = new TShowIncomeRecordExample();
        TShowIncomeRecordExample.Criteria cri = example.createCriteria();
        cri.andMerchantIdEqualTo(request.getMerchantId());
        List<TShowIncomeRecord> tShowIncomeRecords = tShowIncomeRecordMapper.selectByExample(example);
        ArgsUtils.notEmpty(tShowIncomeRecords,
                SgsResponseCode.MERCHANT_UN_INIT_INCOME_RECORD.getResponseCode(),
                SgsResponseCode.MERCHANT_UN_INIT_INCOME_RECORD.getResponseDesc());
        TShowIncomeRecord tShowIncomeRecord = tShowIncomeRecords.get(0);

        TShowIncomeRecord record = new TShowIncomeRecord();
        //今日收益
        boolean judge = judge(tShowIncomeRecord.getUpdatedAt());
        if (judge) {
            record.setTodayOnlineAmount(tShowIncomeRecord.getTodayOnlineAmount().add(trsAmount));
        } else {
            record.setTodayOnlineAmount(trsAmount);
        }
        //累计收益
        record.setOnlineAmount(tShowIncomeRecord.getOnlineAmount().add(trsAmount)); //onLineAmount初始化不能为Null,会造成Null.add()函数报错
        record.setUpdatedBy(request.getMerchantId());
        record.setUpdatedAt(new Date());
        tShowIncomeRecordMapper.updateByExampleSelective(record, example);
    }

    /**
     * 检查UserId在MerchId累计消费是否达到赠送标准
     * @param request
     * @return
     */
    private List<TBizOrder> gettBizOrders(SgsIncreaseCreditRequest request) {
        TBizOrderExample tBizOrderExample = new TBizOrderExample();
        TBizOrderExample.Criteria cra = tBizOrderExample.createCriteria();
        cra.andUserIdEqualTo(request.getUserId());
        cra.andOrderMerchantEqualTo(request.getMerchantId());
        return tBizOrderMapper.selectByExample(tBizOrderExample);
    }

    /**
     * 根据商户号查询该商户的优惠规则
     * @param request
     * @return
     */
    private SgsResultResponse<List<TMerchantDiscountRule>> getListSgsResultResponse(SgsIncreaseCreditRequest request) {
        SgsMerchantDiscountRuleQueryByMerchantIdRequest sgsMerchantDiscountRuleQueryRequest = new SgsMerchantDiscountRuleQueryByMerchantIdRequest();
        assembleSgsCommonHandle.assemble(request, sgsMerchantDiscountRuleQueryRequest);
        sgsMerchantDiscountRuleQueryRequest.setMchId(request.getMerchantId());
        return sgsMerchantDiscountRuleService.queryByMerchantId(sgsMerchantDiscountRuleQueryRequest);
    }

    /**
     * 初始化用户商户优惠记录
     * @param request
     * @param totalDiscount
     * @return
     */
    private SgsResultResponse<String> iniUserMerchantDiscount(SgsIncreaseCreditRequest request, int totalDiscount) {
        SgsUserMerchantDiscountAddRequest sgsUserMerchantDiscountAddRequest = new SgsUserMerchantDiscountAddRequest();
        sgsUserMerchantDiscountAddRequest.setMerchantId(request.getMerchantId());
        sgsUserMerchantDiscountAddRequest.setUserId(request.getUserId());
        sgsUserMerchantDiscountAddRequest.setHadDiscountLevel(request.getHadDiscountLevel());
        sgsUserMerchantDiscountAddRequest.setDiscountAmount(String.valueOf(totalDiscount));
        assembleSgsCommonHandle.assemble(request, sgsUserMerchantDiscountAddRequest);
        return sgsUserMerchantDiscountService.iniUserMerchantDiscount(sgsUserMerchantDiscountAddRequest);
    }

    /**
     * 查询消费用户商户优惠积分(userId,MerchantId)
     * @return
     */
    private SgsResultResponse<TUserMerchantDiscount> queryDiscount(SgsIncreaseCreditRequest request) {
        SgsUserMerchantDiscountRequest sgsUserMerchantDiscountRequest = new SgsUserMerchantDiscountRequest();
        sgsUserMerchantDiscountRequest.setMerchantId(request.getMerchantId());
        sgsUserMerchantDiscountRequest.setUserId(request.getUserId());
        assembleSgsCommonHandle.assemble(request, sgsUserMerchantDiscountRequest);
        return sgsUserMerchantDiscountService.queryUserMerchantDiscount(sgsUserMerchantDiscountRequest);
    }

    /**
     * 调用Increase接口 累加用户商户优惠积分
     * @param request
     * @param totalDiscount
     * @return
     */
    private SgsResultResponse<String> invokeIncreaseUserMerchantDiscount(SgsIncreaseCreditRequest request, int totalDiscount) {
        SgsUserMerchantDiscountRequest sgsUserMerchantDiscountRequest = new SgsUserMerchantDiscountRequest();
        sgsUserMerchantDiscountRequest.setMerchantId(request.getMerchantId());
        sgsUserMerchantDiscountRequest.setUserId(request.getUserId());
        sgsUserMerchantDiscountRequest.setHadDiscountLevel(request.getHadDiscountLevel());
        sgsUserMerchantDiscountRequest.setDiscountAmount(String.valueOf(totalDiscount));
        assembleSgsCommonHandle.assemble(request, sgsUserMerchantDiscountRequest);
        return sgsUserMerchantDiscountService.increaseUserMerchantDiscount(sgsUserMerchantDiscountRequest);
    }

    /**
     * 获取优惠规则, 并判断是否已经送过优惠
     */
    private int getDiscountRule(SgsIncreaseCreditRequest request) {
        List<TMerchantDiscountRule> ruleList = request.getRuleList();
        for (int index = ruleList.size()-1; index >=0; index--) {//检查UserId在MerchId累计消费是否达到赠送标准
            Integer discountAmount = ruleList.get(index).getDiscountAmount();
            if (request.getTotalRecordAmount().compareTo(new BigDecimal(discountAmount)) >= 0 &&
                    discountAmount > request.getHadDiscountLevel()) {
                //更新已经赠送的优惠级别
                request.setHadDiscountLevel(discountAmount);
                return discountAmount;
            }
        }
        return 0;
    }


    /**
     * 获取设备
     * @param request
     * @return
     */
    private DeviceInfoVo getDevice(SgsIncreaseCreditRequest request){
        DeviceInfoVo device = null;
        SgsDeviceQueryRequest target = new SgsDeviceQueryRequest();
        assembleSgsCommonHandle.assemble( request,target);
        target.setDeviceId(request.getDeviceId());
        SgsResultResponse<DeviceInfoVo> devResponse =  sgsDeviceService.queryDeviceInfo(target);
        if(TranslateUtil.isSuccessAbs(devResponse.getErrorCode()) && devResponse.getResult() != null){
            device = devResponse.getResult();
            if(!EnumDeviceState.ONLINE.getStateCode().equals(device.getState())){
                return null;
            }
        }
        return device;
    }

    /**
     * 下单
     * @param request
     * @param device
     * @return
     */
    private TBizOrder settleOrder(SgsIncreaseCreditRequest request, DeviceInfoVo device){
        //下主单
        TMainOrder tMainOrder = new TMainOrder();
        tMainOrder.setOrderId(SeqUtil.getShortSeq(SeqFlagEnum.T_MAIN_ORDER_ID.getCode()));
        tMainOrder.setOrderState(OrderStateEnum.SM_INI.getCode());
        tMainOrder.setOrderType(OrderTypeEnum.INCREASE_CREDIT.getCode());
        tMainOrder.setUserId(request.getUserId());
        tMainOrder.setOrderAmount(new BigDecimal(request.getTrsAmount()));
        tMainOrder.setCreatedAt(request.getReqTime());
        tMainOrder.setUpdatedAt(request.getReqTime());
        int mainOrderNum = tMainOrderMapper.insertSelective(tMainOrder);
        ArgsUtils.positive(mainOrderNum, SgsResponseCode.C_DB_EXCEPTION.getResponseCode(), SgsResponseCode.C_DB_EXCEPTION.getResponseDesc());
        //下业务单
        TBizOrder tBizOrder = new TBizOrder();
        tBizOrder.setOrderId(tMainOrder.getOrderId());
        tBizOrder.setBizOrderId(SeqUtil.getShortSeq(SeqFlagEnum.T_BIZ_ORDER_ID.getCode()));
        tBizOrder.setBizType(OrderTypeEnum.INCREASE_CREDIT.getCode());
        tBizOrder.setBizState(OrderStateEnum.SM_INI.getCode());
        tBizOrder.setBizAmount(new BigDecimal(request.getTrsAmount()));
        tBizOrder.setOrderDevice(device.getDeviceId());
        tBizOrder.setUserId(request.getUserId());
        tBizOrder.setOrderShop(device.getShopId());
        tBizOrder.setOrderMerchant(device.getMerchantId());
        tBizOrder.setCreatedAt(request.getReqTime());
        tBizOrder.setUpdatedAt(request.getReqTime());
        int bizOrderNum = tBizOrderMapper.insertSelective(tBizOrder);
        ArgsUtils.positive(bizOrderNum, SgsResponseCode.C_DB_EXCEPTION.getResponseCode(), SgsResponseCode.C_DB_EXCEPTION.getResponseDesc());
        return tBizOrder;
    }

    /**
     * 获取用户信息
     * @param request
     * @return
     */
    private SgsUserInfoQueryResponse getUserInfo(SgsIncreaseCreditRequest request){
        SgsUserInfoQueryResponse userInfo = null;
        SgsUserInfoQueryRequest target = new SgsUserInfoQueryRequest();
        target.setInitiationID(request.getInitiationID());
        target.setReqTime(request.getReqTime());
        target.setLoginChannel(request.getLoginChannel());
        target.setOpenId(request.getOpenId());
        target.setUserId(request.getUserId());
        SgsResultResponse<SgsUserInfoQueryResponse> userResponse = this.sgsUserInfoService.queryUserInfo(target);
        if(TranslateUtil.isSuccessAbs(userResponse.getErrorCode()) && userResponse.getResult() != null){
            userInfo = userResponse.getResult();
        }
        return userInfo;
    }

    /**
     * 调用TCP消费上分口
     * @param request
     * @param deviceId
     * @param orderId
     * @return
     */
    private boolean invokeTcpIncreaseCredit(SgsIncreaseCreditRequest request,String deviceId,String orderId){
        boolean invokeResult = false;
        TcpIncreaseCreditRequest tcpRequest = new TcpIncreaseCreditRequest();
        tcpRequest.setDeviceId(deviceId);
        tcpRequest.setIncrease(String.valueOf(sequenceMapper.getIncreaseCreditSequence()));
        log.info("3号指令云上分请求Log自增码: {}",tcpRequest.getIncrease());
        tcpRequest.setCoinAmount(request.getTrsAmount());
        tcpRequest.setAmount(request.getTrsAmount());
        SgsResultResponse<String> tcpResponse =  tcpIncreaseCreditService.invoke(tcpRequest);
        if(TranslateUtil.isSuccessAbs(tcpResponse.getErrorCode()) && tcpResponse.getResult() != null){
            invokeResult = true;
        }
        return invokeResult;
    }

    /**
     * 更新订单状态
     * @param request
     */
    private void updateOrder(TBizOrder request){
        //更新主订单
        TMainOrder tMainOrder = new TMainOrder();
        tMainOrder.setOrderState(OrderStateEnum.SM_AFT.getCode());
        tMainOrder.setUpdatedAt(new Date());
        TMainOrderExample tMainOrderExample = new TMainOrderExample();
        TMainOrderExample.Criteria cra1 = tMainOrderExample.createCriteria();
        cra1.andOrderIdEqualTo(request.getOrderId());
        tMainOrderMapper.updateByExampleSelective(tMainOrder,tMainOrderExample);

        //更新业务单
        TBizOrder tBizOrder = new TBizOrder();
        tBizOrder.setBizState(OrderStateEnum.SM_AFT.getCode());
        tBizOrder.setUpdatedAt(new Date());
        TBizOrderExample tBizOrderExample = new TBizOrderExample();
        TBizOrderExample.Criteria cra2 = tBizOrderExample.createCriteria();
        cra2.andBizOrderIdEqualTo(request.getBizOrderId());
        tBizOrderMapper.updateByExampleSelective(tBizOrder,tBizOrderExample);
    }

    /**
     * 判断修改的时间是否是当天：true 当天， false 不是当天
     * @param updatedAt
     * @return
     */
    private boolean judge(Date updatedAt) {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String update = format.format(updatedAt);
        String now = format.format(date);
        String[] updates = update.split("-");
        String[] nows = now.split("-");

        for (int index = 0; index <updates.length; index++) {
            if (Integer.parseInt(updates[index]) != Integer.parseInt(nows[index])) {
                return false;
            }
        }
        return true;
    }
}

